﻿KISSY.add("fgt/ui/popup", function (S, Component, Overlay) {

    var OFFSET = 10;
    function Popup(container, config) {
        var self = this;

        if (S.isUndefined(config)) {
            config = container;
        } else {
            config.srcNode = container;
        }
        Popup.superclass.constructor.call(self, S.merge({ shadow: true, shadowExtLength: 4, zIndex: 99999 }, config || {}));
    }

    Popup.ATTRS = {
        trigger: {
            setter: function (v) {
                return S.one(v);
            }
        },
        showTriggerType: { value: "mouseenter" },
        hideTriggerType: { value: "mouseleave" },
        showDelay: { value: 0 },
        hideDelay: { value: 100 },
        alignNode: {
            setter: function (v) {
                return S.one(v);
            }
        },
        alignDirCfg: { value: "auto" }, // "auto", "t", "b"
        alignCfg: {
            value: { t: { points: ["tc", "bl"], offset: [0, 0] }, b: { points: ["bc", "tl"], offset: [0, 0]} }
        },
        ajaxLoadCfg: {
            value: {
                enable: false,
                refresh: false
            }
        },
        ajaxLoadEffect: {
            value: {
                loadingHtml: "<div class='loading' style='width: 200px; height: 100px;'><div class='text'><span>加载中...</span></div></div>",
                loadFailureHtml: "<div class='load-failure' style='width: 200px; height: 100px;'><div class='text'><span>加载失败</span></div></div>"
            }
        },
        showArrow: { value: false }
    };

    S.extend(Popup, Overlay, {
        initializer: function () {
            var self = this;

            var trigger = self.get("trigger");
            if (trigger) {
                self._bindTrigger();
                self.on('bindUI', function () {
                    self._bindContainerMouse();
                });
            }

            self.isRender = false;
        },

        _render: function () {
            var self = this,
                showArrow = self.get("showArrow");

            self.render();  //must invoke render() before any operations of access DOM node
            if (showArrow) {
                self._addArrow();
            }
            self.isRender = true;
        },

        _addArrow: function () {
            var self = this,
            //contentEl = self.get("contentEl"),
                el = self.get("el"),
                prefixCls = self.get("prefixCls");
            //contentEl.append("<div class='" + prefixCls + "arrow'></div>");
            el.append("<div class='" + prefixCls + "arrow'></div>");
        },

        _setArrowDirection: function () {
            var self = this,
                direction = self.get("alignDir"),
            //contentEl = self.get("contentEl"),
                el = self.get("el"),
                arrowCls = self.get("prefixCls") + "arrow",
            //arrowNode = contentEl.all("." + arrowCls);
                arrowNode = el.all("." + arrowCls);
            if (direction == "t") {
                arrowNode.removeClass(arrowCls + "-top");
                arrowNode.addClass(arrowCls + "-bottom");
            }
            else if (direction == "b") {
                arrowNode.removeClass(arrowCls + "-bottom");
                arrowNode.addClass(arrowCls + "-top");
            }
        },

        _judgeAlign: function () {
            var self = this,
                alignNode = self.get("alignNode"),
                alignDirCfg = self.get("alignDirCfg");

            if (alignDirCfg == "auto") {
                var el = self.get("el"),
                elHeight = el.outerHeight(),
                win = S.all(window),
                alignNodeOffset = alignNode.offset(),
                alignNodeWidth = alignNode.width(),
                topHeight = alignNodeOffset.top - win.scrollTop();
                if (topHeight >= (elHeight + OFFSET)) {
                    self.set("alignDir", "t");
                }
                else {
                    self.set("alignDir", "b");
                }
            }
            else {
                self.set("alignDir", alignDirCfg);
            }
        },

        _setAlign: function () {
            var self = this,
                direction = self.get("alignDir"),
                alignNode = self.get("alignNode"),
                alignCfg = self.get("alignCfg"),
                dirCfg = alignCfg[direction];
            if (direction == "t") {
                //self.align(alignNode, dirCfg.points, [dirCfg.offset[0], -OFFSET + dirCfg.offset[1]]);
                self.set("align", {
                    node: alignNode,
                    points: dirCfg.points,
                    offset: [dirCfg.offset[0], -OFFSET + dirCfg.offset[1]]
                });
            }
            else if (direction == "b") {
                //self.align(alignNode, dirCfg.points, [dirCfg.offset[0], OFFSET + dirCfg.offset[1]]);
                self.set("align", {
                    node: alignNode,
                    points: dirCfg.points,
                    offset: [dirCfg.offset[0], OFFSET + dirCfg.offset[1]]
                });
            }
        },

        reposition: function () {
            var self = this,
                showArrow = self.get("showArrow");

            self._judgeAlign();
            self._setAlign();
            if (showArrow) {
                self._setArrowDirection();
            }
            self.resizeShadow();
        },

        _ajaxLoad: function () {
            var self = this,
                J = jQuery,
                contentEl = self.get("contentEl"),
                ajaxLoadCfg = self.get("ajaxLoadCfg"),
                ajaxLoadEffect = self.get("ajaxLoadEffect"),
            //prefixCls = self.get("prefixCls"),
            //arrowCls = prefixCls + "arrow",
                url = ajaxLoadCfg.url,
                loadingHtml = ajaxLoadEffect.loadingHtml,
                loadFailureHtml = ajaxLoadEffect.loadFailureHtml;

            if ((ajaxLoadCfg.refresh && !contentEl.hasClass("loading")) || (!contentEl.hasClass("loading") && !contentEl.hasClass("loaded"))) {
                var resultCode = FGT.core.constant.jsonResultCode;
                if (ajaxLoadCfg.url) {
                    J.ajax({
                        url: url,
                        type: "GET",
                        cache: false,
                        beforeSend: function (jqXHR, settings) {
                            var b = contentEl;
                            b.html(loadingHtml);
                            b.addClass("loading");
                            self.reposition();
                        },
                        success: function (data, textStatus, jqXHR) {
                            var b = contentEl;
                            if (data.Result === resultCode.SUCCESS) {
                                b.html(data.Content);
                                b.addClass("loaded");
                            }
                            else {
                                b.html(loadFailureHtml);
                            }
                            b.removeClass("loading");
                            self.reposition();
                        },
                        error: function (jqXHR, textStatus, errorThrown) {
                            var b = contentEl;
                            b.html(loadFailureHtml);
                            b.removeClass("loading");
                            self.reposition();
                        }
                    });
                }
            }
        },

        _bindTrigger: function () {
            var self = this,
                trigger = self.get("trigger"),
                timer,
                showArrow = self.get("showArrow");

            self._showPopup = function (event) {
                self._clearHiddenTimer();

                timer = S.later(function () {
                    var alignNode = self.get("alignNode");
                    if (!alignNode) {
                        return;
                    }
                    if (!self.isRender) {
                        self._render();
                    }
                    self._judgeAlign();
                    self._setAlign();
                    if (showArrow) {
                        self._setArrowDirection();
                    }
                    if (self.get("ajaxLoadCfg").enable) {
                        self._ajaxLoad();
                    }
                    self.show();
                    timer = undefined;
                }, self.get("showDelay"));
            };

            trigger.on(self.get("showTriggerType"), self._showPopup);


            self._hidePopup = function () {
                if (timer) {
                    timer.cancel();
                    timer = undefined;
                }

                self._setHiddenTimer();
            };

            trigger.on(self.get("hideTriggerType"), self._hidePopup);
        },

        _bindContainerMouse: function () {
            var self = this;

            self.get('el').on('mouseleave', self._setHiddenTimer, self)
                .on('mouseenter', self._clearHiddenTimer, self);
        },

        _setHiddenTimer: function () {
            var self = this;
            self._hiddenTimer = S.later(function () {
                self.hide();
            }, self.get("hideDelay"));
        },

        _clearHiddenTimer: function () {
            var self = this;
            if (self._hiddenTimer) {
                self._hiddenTimer.cancel();
                self._hiddenTimer = undefined;
            }
        },

        destructor: function () {
            var self = this;
            var t = self.get("trigger");
            if (t) {
                if (self.__showPopup) {
                    t.detach(self.get("showTriggerType"), self._showPopup);
                }
                if (self._hidePopup) {
                    t.detach(self.get("hideTriggerType"), self._hidePopup);
                }
            }
            if (self.get('el')) {
                self.get('el').detach('mouseleave', self._setHiddenTimer, self)
                    .detach('mouseenter', self._clearHiddenTimer, self);
            }
        }
    });


    Component.UIStore.setUIByClass("popup", {
        priority: Component.UIStore.PRIORITY.LEVEL1,
        ui: Popup
    });

    return Popup;
}, {
    requires: ["component", "overlay"]
});